class KogukondController < ApplicationController
  include Math
  include Comparable

  before_filter :authorize, :except => [:getGraphML, :queryGraphML, :index]

  HIGHLIGHT = "1"
  NOHIGHLIGHT = "2"

  # index is used by the applet for passing parameters via a query string
  def index
    queryGraphML()
  end

  def getGraphML
    # TODO Is this method called from anywhere? Can we replace it with a call to queryGraphML and pass no parameters?
    # if we are coming into here directly from the applet or application, set community_id
    if session[:community_id] == nil
      session[:community_id] = 1
    end

    @nodes  = Node.find(:all,  :conditions => ["community_id = ?", session[:community_id]])
    @edges  = Edge.find(:all,  :conditions => ["community_id = ?", session[:community_id]])
    @nodes.each do |node|
      node.highlight = NOHIGHLIGHT
    end
    output = buildXML()
    render :text => output
  end

  def queryGraphML
    # if we are coming into here directly from the applet and not through the rails app there is no session
    # so set community_id to default community
    if session[:community_id] == nil
      session[:community_id] = 1
    end
    @queryGender  = @params[:gender]
    if @queryGender.nil?
      @queryGender = ""
    end
    @queryFromAge = @params[:fromAge]
    if @queryFromAge.nil?
      @queryFromAge = ""
    end
    @queryToAge = @params[:toAge]
    if @queryToAge.nil?
      @queryToAge = ""
    end
    @queryFacets = @params[:facets]
    if @queryFacets.nil?
      @queryFacets = ""
    end
    queryNodes()
    output = buildXML()
    render :text => output
  end

  def queryMap
    if request.post?
      @queryParams       = params[:queryParam]
      @queryGender       = @queryParams[:gender]
      @queryFromAge      = @queryParams[:fromAge]
      @queryToAge        = @queryParams[:toAge]
      @queryFacets       = @queryParams[:facet]
      @queryCenterNodeId = @queryParams[:nodeId]
      @queryDistance     = @queryParams[:distance]

      if @queryGender == "" and @queryFromAge == "" and @queryToAge == "" and @queryFacets == "" and @queryCenterNodeId == ""
        flash[:notice] = 'Please enter query criteria for the map.'
        redirect_to(:action => 'queryMap')
      else
        # put parameters into session variables to have available in displayNodeMap
        session[:queryParams] = @queryParams
        redirect_to(:action => 'displayNodeMap')
      end
    end
  end

  def displayNodeMap
    @queryParams       = session[:queryParams]
    @queryGender       = @queryParams[:gender]
    @queryFromAge      = @queryParams[:fromAge]
    @queryToAge        = @queryParams[:toAge]
    @queryFacets       = @queryParams[:facet]
    @queryCenterNodeId = @queryParams[:nodeId]
    @queryDistance     = @queryParams[:distance]

    queryNodes()

    # Go through all the nodes and put nodes that have been flagged as highlighted into the places array
    @places = Array.new
    if @queryCenterNodeId == ""
      @nodes.each do |node|
        if node.highlight == HIGHLIGHT and not node.lat=="" and not node.long==""
          @places.push(:latitude=>node.lat,:longitude=> node.long, :description=>node.name+": "+node.address)
        end
      end
    else
      # TODO: change lat/long datatype from string to float
      centerNode = Node.find(@queryCenterNodeId)
      queryDistance_Float = @queryDistance.to_f
      lowerBoundLat  = centerNode.lat.to_f  - (queryDistance_Float / 70) #approximately 70 miles per degree latitude
      upperBoundLat  = centerNode.lat.to_f  + (queryDistance_Float / 70)
      #puts(centerNode.lat)
      #puts(lowerBoundLat)
      #puts(upperBoundLat)
      lowerBoundLong = centerNode.long.to_f - (queryDistance_Float / (cos(centerNode.lat.to_f * 3.14/180) * 70)) # convert lat degrees to radians for cosine calc
      upperBoundLong = centerNode.long.to_f + (queryDistance_Float / (cos(centerNode.lat.to_f * 3.14/180) * 70))
      #puts(centerNode.long)
      #puts(lowerBoundLong)
      #puts(upperBoundLong)
      # if no other query criteria entered other than Center Node ID then don't check if the highlight flag is set
      if @queryGender == "" and @queryFromAge == "" and @queryToAge == "" and @queryFacets == ""
        @nodes.each do |node|
          if node.lat.to_f.between?(lowerBoundLat, upperBoundLat) and node.long.to_f.between?(lowerBoundLong, upperBoundLong)
            @places.push(:latitude=>node.lat,:longitude=> node.long, :description=>node.name+": "+node.address)
          end
        end
      else
        @nodes.each do |node|
          if node.highlight == HIGHLIGHT and node.lat.to_f.between?(lowerBoundLat, upperBoundLat) and node.long.to_f.between?(lowerBoundLong, upperBoundLong)
            @places.push(:latitude=>node.lat,:longitude=> node.long, :description=>node.name+": "+node.address)
          end
        end
      end
    end

    if @places.length == 0
      flash[:notice] = 'No Nodes meet your query criteria.  Please try again with different parameters.'
      redirect_to(:action => 'queryMap')
    end
  end

  def queryNodes
    @nodes  = Node.find(:all,  :conditions => ["community_id = ?", session[:community_id]])
    @edges  = Edge.find(:all,  :conditions => ["community_id = ?", session[:community_id]])
    @facets = Facet.find(:all, :conditions => ["community_id = ? and facet = ?", session[:community_id], @queryFacets])

    @nodes.each do |node|
      node.highlight = NOHIGHLIGHT
      if not @queryGender == ""
        if node.gender == @queryGender
          node.highlight = HIGHLIGHT
        else
          node.highlight = NOHIGHLIGHT
          next
        end
      end

      if not @queryFromAge == ""
        if node.born_on.nil?
          # don't calc age if DOB is nil
          age = 0
        else
          age = ((Date.today.strftime("%Y%m%d").to_i - node.born_on.strftime("%Y%m%d").to_i)/10000).to_i
        end

        if (@queryFromAge.to_i <= age and age <= @queryToAge.to_i)
          node.highlight = HIGHLIGHT
        else
          node.highlight = NOHIGHLIGHT
          next
        end
      end

      if not @queryFacets == ""
        for facet in @facets
          if node.id == facet.node_id
            node.highlight = HIGHLIGHT
            break
          else
            node.highlight = NOHIGHLIGHT
          end
        end
      end
    end
  end #end method

  def buildXML()
    buffer = ""

    # create GraphML xml file
    xml = Builder::XmlMarkup.new(:target => buffer, :indent => 1)
    xml.instruct!
    xml.comment! "Hello kogukond!"
    xml.graphml(:xmlns => "http://graphml.graphdrawing.org/xmlns") do
      xml.graph(:edgefault => "undirected") do
        xml.key('id="name"      for = "node" attr.name ="name"      attr.type = "string"')
        xml.key('id="gender"    for = "node" attr.name ="gender"    attr.type = "string"')
        xml.key('id="highlight" for = "node" attr.name ="highlight" attr.type = "string"')

        @nodes.each do |node|
          xml.node(:id => node.id) do
            xml.data(node.name,   :key => "name")
            xml.data(node.gender, :key => "gender")
            xml.data(node.highlight, :key => "highlight")
          end
        end

        @edges.each do |edge|
          xml.edge(:source => edge.source, :target => edge.target)
        end
      end
    end
    # clean up the XML so it is acceptable to prefuse
    output1 = buffer.gsub("<key>id", "<key id")
    output2 = output1.gsub("</key>",  "/>")
  end

end #end class